/*
  alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"MULTIMEDIA MPlayer demux_open_vqf TwinVQ file handling buffer overflow attempt"; flowbits:isset,file.vqf; flow:to_client,established; content:"TWIN97012000"; metadata:policy balanced-ips drop, policy security-ips drop, service http; reference:cve,2008-5616; reference:bugtraq,32822; reference:url,trapkit.de/advisories/TKADV2008-014.txt; classtype:attempted-user;)
*/

/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG
#ifdef DEBUG
#define DEBUG_SO(code) code
#else
#define DEBUG_SO(code)
#endif

/* declare detection functions */
int rule17300eval(void *p);

/* declare rule data structures */
/* precompile the stuff that needs pre-compiled */
/* flowbits:isset "file.vqf"; */
static FlowBitsInfo rule17300flowbits0 =
{
    "file.vqf",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule17300option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule17300flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule17300flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule17300option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule17300flow1
    }
};
// content:"TWIN97012000"; 
static ContentInfo rule17300content2 = 
{
    (uint8_t *) "TWIN97012000", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED, /* flags */ // XXX - need to add CONTENT_FAST_PATTERN support
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule17300option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule17300content2
    }
};

/* references for sid 17300 */
/* reference: bugtraq "32822"; */
static RuleReference rule17300ref1 = 
{
    "bugtraq", /* type */
    "32822" /* value */
};

/* reference: cve "2008-5616"; */
static RuleReference rule17300ref2 = 
{
    "cve", /* type */
    "2008-5616" /* value */
};

/* reference: url "trapkit.de/advisories/TKADV2008-014.txt"; */
static RuleReference rule17300ref3 = 
{
    "url", /* type */
    "trapkit.de/advisories/TKADV2008-014.txt" /* value */
};

static RuleReference *rule17300refs[] =
{
    &rule17300ref1,
    &rule17300ref2,
    &rule17300ref3,
    NULL
};

/* metadata for sid 17300 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule17300service1 = 
{
    "service http"
};

static RuleMetaData rule17300policy1 =
{
   "policy max-detect-ips drop"
};

static RuleMetaData *rule17300metadata[] =
{
    &rule17300service1,
    &rule17300policy1,
    NULL
};

RuleOption *rule17300options[] =
{
    &rule17300option0,
    &rule17300option1,
    &rule17300option2,
    NULL
};

Rule rule17300 = {
   
   /* rule header, akin to => tcp any any -> any any               */{
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid (HARDCODED!!!) */
       17300, /* sigid */
       5, /* revision */
   
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-MULTIMEDIA MPlayer demux_open_vqf TwinVQ file handling buffer overflow attempt",     /* message */
       rule17300refs /* ptr to references */
       ,rule17300metadata
   },
   rule17300options, /* ptr to rule options */
   &rule17300eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule17300eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *beg_of_payload, *end_of_payload;
    const uint8_t *end_of_subchunk = 0;
    const uint8_t *temp;

    uint32_t total_subchunk_size = 0;
    uint32_t cur_subchunk_size = 0;
    
    if(sp == NULL)
        return RULE_NOMATCH;

    // flowbits:isset "file.vqf";
    if (processFlowbits(p, rule17300options[0]->option_u.flowBit) > 0) {
        // flow:established, to_client;
        if (checkFlow(p, rule17300options[1]->option_u.flowFlags) > 0 ) {
            // content:"TWIN97012000";
            if (contentMatch(p, rule17300options[2]->option_u.content, &cursor_normal) > 0) {

                if (getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                    return RULE_NOMATCH;

                if (cursor_normal + 4 > end_of_payload)
                    return RULE_NOMATCH;
                
                total_subchunk_size = read_big_32(cursor_normal);               
                DEBUG_SO(printf("total_subchunk_size=0x%08x\n", total_subchunk_size));

                temp = cursor_normal + total_subchunk_size + 4; /* 4 byte total_subchunk_size field */
                             
                 /* integer overflow check */ 
                if (temp > cursor_normal)
                    end_of_subchunk = temp;
                else
                    return RULE_NOMATCH;                  
                                                 
                if (end_of_subchunk > end_of_payload) 
                    end_of_subchunk = end_of_payload;
                                                  
                cursor_normal += 8; /* 4 byte total_subchunk_size + 4 byte subchunk ID */
                                 /* This makes our jumps line up with the size fields, skipping the IDs */
                
                while (cursor_normal + 4 <= end_of_subchunk) 
                {
                    cur_subchunk_size = read_big_32(cursor_normal);
                    DEBUG_SO(printf("cur_subchunk_size=0x%08x\n", cur_subchunk_size));
                    
                    if (cur_subchunk_size > total_subchunk_size)                          
                        return RULE_MATCH;

                    temp = cursor_normal + cur_subchunk_size + 8; /* 4 byte subchunk length + 4 byte subchunk ID */

                    if (temp > cursor_normal)
                        cursor_normal = temp;
                    else
                        return RULE_NOMATCH;
                }
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule17300,
    NULL
};
*/
